package net.towee.client.com.dashboard.presenter;

import java.util.ArrayList;
import java.util.List;

import net.towee.client.com.dashboard.BoardEditor;
import net.towee.client.com.dashboard.DashBoard;
import net.towee.client.managers.AccountHelper;
import net.towee.client.managers.DashBoardManager;
import net.towee.model.account.AccountGroup;
import net.towee.model.account.Board;
import net.towee.model.account.impl.BoardImpl;
import net.towee.model.group.GroupIdentity;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.inject.Inject;

public class BoardEditorPresenter implements BoardEditor, ClickHandler {

	public interface Display extends IsWidget {
		void setName(String name);

		String getName();

		void setAttachedGroups(List<GroupIdentity> groups);

		List<GroupIdentity> getAttachedGroups();

		/**
		 * Set the list of groups where user already entered, EXPECT already
		 * attached to board groups.
		 * 
		 * @param groups
		 */
		void setAvailableGroups(List<GroupIdentity> groups);

		HasClickHandlers getApplyButton();

		HasClickHandlers getDeleteButton();

		void emptyName();

		void existsName();

		void onBoardOperationDone();
		
		void showEditor();

	}

	// Injected
	private final Display display;
	private final DashBoardManager boardManager;
	private final AccountHelper account;
	private final DashBoard dashboard;

	private Board currentBoard;

	@Inject
	public BoardEditorPresenter(Display display, DashBoardManager boardManager, AccountHelper account,
			DashBoard dashboard) {
		this.display = display;
		this.boardManager = boardManager;
		this.account = account;
		this.dashboard = dashboard;

		display.getApplyButton().addClickHandler(this);
		display.getDeleteButton().addClickHandler(this);
	}

	@Override
	public void go(HasWidgets container) {
		// Add available groups
		if(currentBoard == null) {
			// Set available groups
			List<GroupIdentity> avlGroups = new ArrayList<GroupIdentity>();
			for (AccountGroup g : account.getAccount().getGroups().getGroupsList()) {
				avlGroups.add(g.getGroupIdentity());
			}
			display.setAvailableGroups(avlGroups);
		}
		
		// Show editor
		display.showEditor();
	}

	@Override
	public void setBoard(Board currentBoard) {
		this.currentBoard = currentBoard;

		// Set name and attached groups
		display.setName(currentBoard.getName());
		display.setAttachedGroups(currentBoard.getAttachedGroups());

		// Set available groups
		List<GroupIdentity> avlGroups = new ArrayList<GroupIdentity>();
		for (AccountGroup g : account.getAccount().getGroups().getGroupsList()) {
			if (!currentBoard.getAttachedGroups().contains(g.getGroupIdentity()))
				avlGroups.add(g.getGroupIdentity());
		}
		display.setAvailableGroups(avlGroups);
	}

	@Override
	public void onClick(ClickEvent event) {
		if (event.getSource().equals(display.getDeleteButton())) {
			Preconditions.checkNotNull( currentBoard, "null current board" );
			
			// Remove board
			boardManager.removeBoard(currentBoard.getId(), new AsyncCallback<Boolean>() {
				@Override
				public void onFailure(Throwable caught) {
				}

				@Override
				public void onSuccess(Boolean result) {
					display.onBoardOperationDone();
				}
			});
		}
		// Apply changes
		else if (event.getSource().equals(display.getApplyButton())) {
			if (Strings.isNullOrEmpty(display.getName()))
				display.emptyName();
			else {
				// Create board object for checking name existing
				Board b = new BoardImpl("null", display.getName());

				// Check board name
				if (account.getAccount().getBoardsContainer().hasBoard(b) 
						&& (currentBoard == null || !currentBoard.getName().equals(display.getName())))
					display.existsName();
				else {
					// Async callback for next operation
					AsyncCallback<Board> callback = new AsyncCallback<Board>() {
						@Override
						public void onFailure(Throwable caught) {
						}

						@Override
						public void onSuccess(Board result) {
							display.onBoardOperationDone();
							dashboard.showBoard(result);
						}
					};

					// Update board
					if (currentBoard != null) {
						// Set name and remove old groups
						currentBoard.setName(display.getName());
						currentBoard.getAttachedGroups().clear();

						// Add new groups
						for (GroupIdentity g : display.getAttachedGroups())
							currentBoard.attachGroup(g);

						// Update board
						boardManager.updateBoard(currentBoard, callback);
					}
					// Create board
					else {
						for (GroupIdentity g : display.getAttachedGroups())
							b.attachGroup(g);

						// Add board
						boardManager.addBoard(b, callback);
					}
				}
			}
		}
	}

}
